using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace MicrosoftFrance.MCS.EPM2007
{
    class GeneralHelper
    {
        public static string FormatTimeLog()
        {
            DateTime dtNow = DateTime.Now;
            String Year = dtNow.Year.ToString();
            String Month = FormatTwoDigits(dtNow.Month);
            String Day = FormatTwoDigits(dtNow.Day);
            String Hour = FormatTwoDigits(dtNow.Hour);
            String Minutes = FormatTwoDigits(dtNow.Minute);
            String Seconds = FormatTwoDigits(dtNow.Second);
            return Year + Month + Day + "-" + Hour + Minutes + Seconds;
        }
        public static string FormatTwoDigits(int source)
        {
            if (source < 10)
                return String.Format("0{0}", source.ToString());
            else
                return source.ToString();
        }

        // Write all contents of a table collection to the console
        public static void WriteTablesToConsole(DataTableCollection theTables, AppLog appLog)
        {
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            foreach (System.Data.DataTable table in theTables)
            {
                int[] columnWidths = new int[table.Columns.Count];
                int tableWidth = 0;
                string dataString;
                Console.WriteLine("Table: " + table.TableName);
                appLog.WriteLine("Table: " + table.TableName, false);

                StringBuilder tableRow = new StringBuilder();
                for (int i = 0; i < table.Columns.Count; i++)
                {
                    columnWidths[i] = GetColumnWidth(table.Columns[i]);
                    tableRow.Append(table.Columns[i].ColumnName.PadRight(columnWidths[i]));
                    tableWidth += columnWidths[i];
                }
                tableWidth += 1;
                Console.BufferWidth = (Console.BufferWidth > tableWidth ? Console.BufferWidth : tableWidth);
                tableRow.Append("\r\n");
                Console.Write(tableRow.ToString());
                appLog.WriteLine(tableRow.ToString(), false);

                foreach (DataRow row in table.Rows)
                {
                    tableRow = new StringBuilder();
                    for (int i = 0; i < table.Columns.Count; i++)
                    {
                        dataString = row[i].ToString();
                        if (dataString.Length >= columnWidths[i])
                            dataString = dataString.Substring(0, columnWidths[i] - 1);
                        tableRow.Append(dataString.PadRight(columnWidths[i]));
                    }
                    tableRow.Append("\r\n");
                    Console.Write(tableRow.ToString());
                    appLog.WriteLine(tableRow.ToString(), false);
                }
                Console.Write("\r\n".PadLeft(tableWidth, '-'));
                appLog.WriteLine("\r\n".PadLeft(tableWidth, '-'), false);
            }
            Console.ResetColor();
        }
        
        // Helper function for WriteTablesToConsole
        private static int GetColumnWidth(DataColumn column)
        {
            // Note: may not handle byte[]data types well
            const int MAX_COL_WIDTH = 40;
            int dataWidth = 0;

            //return 12 for numbers, 30 for dates, and string width for strings.
            switch (column.DataType.UnderlyingSystemType.ToString())
            {
                case "System.Boolean":
                case "System.Byte":
                case "System.Byte[]":
                case "System.Char":
                case "System.Decimal":
                case "System.Double":
                case "System.Int16":
                case "System.Int32":
                case "System.Int64":
                case "System.SByte":
                case "System.Single":
                case "System.UInt16":
                case "System.UInt32":
                case "System.UInt64":
                    dataWidth = 12;
                    break;
                case "System.DateTime":
                case "System.TimeSpan":
                    dataWidth = 30;
                    break;
                case "System.Guid":
                    dataWidth = 37;
                    break;
                case "System.String":
                    // If it has a maxlength, use it
                    if (column.MaxLength > 0)
                    {
                        dataWidth = column.MaxLength;
                    }
                    else
                    {
                        // Otherwise use the max col width
                        dataWidth = MAX_COL_WIDTH;
                    }
                    break;
                default:
                    dataWidth = column.ColumnName.Length;
                    break;
            }
            // truncate if over the max length
            if (dataWidth > MAX_COL_WIDTH)
            {
                dataWidth = MAX_COL_WIDTH;
            }
            // always be at least as wide as the colum name
            return (column.ColumnName.Length > (dataWidth) ? column.ColumnName.Length + 1 : dataWidth);
        }

        public static void WriteTablesFormated(string title, DataTableCollection theTables, AppLog appLog)
        {
            WriteSeparator();
            Console.WriteLine(title);
            appLog.WriteLine(title, false);
            WriteTablesToConsole(theTables, appLog);
        }

        public static void WriteSeparator()
        {
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine("".PadRight(Console.BufferWidth, '='));
            Console.ResetColor();
        }

        public static int GenerateRandomInt(int maxValue)
        {
            Random randObj = new Random(DateTime.Now.Millisecond);
            return randObj.Next(maxValue);
        }

        public static bool GenerateRandomBoolean()
        {
            Random randObj = new Random(DateTime.Now.Millisecond);
            return randObj.NextDouble() > 0.5;
        }

        public static string SetPortforImpersonation(string psUrl, int sspPort)
        {
            Uri ServerUri = new Uri(psUrl);

            psUrl = Regex.Replace(psUrl, ServerUri.Authority, ServerUri.Host + ":" + sspPort.ToString(), RegexOptions.IgnoreCase);
            psUrl = Regex.Replace(psUrl, ServerUri.LocalPath, "", RegexOptions.IgnoreCase);
            return AppendToUrl(psUrl);
        }

        private static string AppendToUrl(string psUrl)
        {
            if (!psUrl.EndsWith("/")) psUrl += "/";
            return psUrl;
        }
/*
        public static void SetImpersonation(bool isWindowsAccount, string userNTAccount, Guid resourceGuid, Guid siteId)
        {
            string baseUrl = SetPortforImpersonation(ProjectServerURL);
            string addUrl = ImpersonationSite + "/PSI/";

            statusing.Url = (baseUrl + addUrl + "Statusing.asmx");
            timesheet.Url = (baseUrl + addUrl + "Timesheet.asmx");

            Guid trackingGuid = Guid.NewGuid();
            string lcid = "1033";

            StatusingDerived.SetImpersonationContext(isWindowsAccount, userNTAccount, resourceGuid, trackingGuid, siteId, lcid);
            TimesheetDerived.SetImpersonationContext(isWindowsAccount, userNTAccount, resourceGuid, trackingGuid, siteId, lcid);
        }
*/
        /// <summary>
        /// Executes a Transact-SQL statement against the Connection and returns the number of rows affected.
        /// </summary>
        /// <param name="connectionString">The connection used to open the SQL Server database.</param>
        /// <param name="cmdText">A <see cref="string"/> containing the name of the stored procedure. Can't be be <b>null</b>.</param>
        /// <returns>The number of rows affected.</returns>
        public static int ConnectAndExecuteNonQuery(string connectionString, string cmdText, StreamWriter sw)
        {
            int nReturn = -1;
            SqlConnection connection = new SqlConnection(connectionString);
            SqlCommand sc = new SqlCommand(cmdText, connection);

            try
            {
                connection.Open();

                nReturn = sc.ExecuteNonQuery();
            }
            catch(SqlException ex)
            {
                AppLog.WriteLine(sw, string.Format("SqlException : {0}", ex.Message));
            }
            catch (Exception ex)
            {
                AppLog.WriteLine(sw, string.Format("Exception : {0}", ex.Message));
            }
            finally
            {
                connection.Close();
                connection.Dispose();
            }
            return nReturn;
        }

        public static long Wait(long waitTime)
        {
            long tics = 0;
            Stopwatch timePerOp = new Stopwatch();
            timePerOp.Start();
            do
            {
                tics = timePerOp.ElapsedMilliseconds;
            } while (tics < waitTime);
            timePerOp.Stop();

            return tics;
        }
    }
}
